/*
 * Copyright (c) Huawei Device Co., Ltd. 2023. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "common_utils.h"
#include <securec.h>
#include <sstream>
#include <fstream>
#include <iostream>
#include "loghelper.h"
#include "ipc_skeleton.h"
namespace OHOS {
namespace SE {

std::string CommonUtils::BytesArrayToHexString(const uint8_t *src, uint32_t length)
{
    // convert byte array to hex string.
    std::string result = "";
    if (length <= 0) {
        return result;
    }
    const std::string hexKeys = "0123456789ABCDEF";
    for (uint32_t i = 0; i < length; i++) {
        result.push_back(hexKeys[(src[i] & 0xF0) >> HALF_BYTE_SHIFT]);
        result.push_back(hexKeys[src[i] & 0x0F]);
    }
    DebugLog("CommonUtils::BytesArrayToHexString result = %{public}s", result.c_str());
    return result;
}

void CommonUtils::HexStringToBytesArray(const std::string &src, std::vector<uint8_t> &bytes)
{
    // convert hex string to byte array.
    if (src.empty()) {
        return;
    }

    uint32_t bytesLen = src.length() / HEX_BYTE_LEN;
    std::string strByte;
    unsigned int srcIntValue;
    for (uint32_t i = 0; i < bytesLen; i++) {
        strByte = src.substr(i * HEX_BYTE_LEN, HEX_BYTE_LEN);
        if (sscanf_s(strByte.c_str(), "%x", &srcIntValue) <= 0) {
            bytes.clear();
            return;
        }
        bytes.push_back(static_cast<uint8_t>(srcIntValue & 0xFF));
    }
}

std::string CommonUtils::UnsignedCharToHexString(const uint8_t src)
{
    // convert the hex byte to string.
    std::string result = "";
    const std::string hexKeys = "0123456789ABCDEF";
    result.push_back(hexKeys[(src & 0xF0) >> HALF_BYTE_SHIFT]);
    result.push_back(hexKeys[src & 0x0F]);
    return result;
}

uint32_t CommonUtils::GetHexStringLength(const std::string &src)
{
    // get the hex string length, the bytes.
    if (src.empty()) {
        return 0;
    }
    return src.length() / HEX_BYTE_LEN;
}

uint8_t CommonUtils::GetHexStrByte(const std::string &src, uint32_t index)
{
    // get the specific byte from the hex string.
    if (src.empty() || index >= (src.length() - 1)) {
        return 0;
    }
    std::string strByte = src.substr(index * HEX_BYTE_LEN, HEX_BYTE_LEN);
    unsigned int srcIntValue;
    if (sscanf_s(strByte.c_str(), "%x", &srcIntValue) <= 0) {
        return 0;
    }
    return static_cast<uint8_t>(srcIntValue & 0xFF);
}

uint8_t CommonUtils::GetApduRespSw1(const std::string &apduResp)
{
    // get the response status word first byte from the reponse data of secure element.
    if (apduResp.empty()) {
        return 0xff;
    }
    uint32_t bytesLen = apduResp.length() / HEX_BYTE_LEN;
    if (bytesLen >= APDU_SW_BYTES) {
        return GetHexStrByte(apduResp, bytesLen - APDU_SW_BYTES);
    }
    return 0xff;
}

uint8_t CommonUtils::GetApduRespSw2(const std::string &apduResp)
{
    // get the response status word second byte from the reponse data of secure element.
    if (apduResp.empty()) {
        return 0xff;
    }
    uint32_t bytesLen = apduResp.length() / HEX_BYTE_LEN;
    if (bytesLen >= APDU_SW_BYTES) {
        return GetHexStrByte(apduResp, bytesLen - 1); // the last bytes
    }
    return 0xff;
}

bool CommonUtils::IsApduRespSuccess(const std::string &apduResp)
{
    // check if the status word is 9000 or not.
    if (GetHexStringLength(apduResp) < APDU_SW_BYTES) {
        return false;
    }

    // 9000 is successful status word defined in ISO7816.
    return GetApduRespSw1(apduResp) == 0x90 && GetApduRespSw2(apduResp) == 0x00;
}

ErrorCode CommonUtils::IntToErrorCode(const int &statusCode)
{
    return ErrorCode(statusCode);
}

std::string CommonUtils::GetUniqueTag()
{
    uint32_t callingTokenId = IPCSkeleton::GetCallingTokenID();
    uint32_t callingPid = IPCSkeleton::GetCallingPid();
    return (std::to_string(callingTokenId) + std::to_string(callingPid));
}

std::string CommonUtils::GetLocalTimeStampWithDate()
{
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
    auto value = now_ms.time_since_epoch().count();
    auto ms = value % 1000;

    time_t now_c = std::chrono::system_clock::to_time_t(now);
    tm *now_tm = localtime(&now_c);
    if (now_tm == nullptr) {
        ErrorLog("now_tm is nullptr");
        return "";
    }
    const uint16_t timeLen = sizeof("YYYY-MM-DD HH:MM:SS");
    char buffer[timeLen];
    std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", now_tm);
    std::stringstream ss;
    uint8_t keepBit = 3;
    ss << buffer << "." << std::setw(keepBit) << std::setfill('0') << ms;
    return ss.str();
}

uint32_t CommonUtils::GetFileSize(const std::string &fileNamePath)
{
    std::ifstream fin(fileNamePath, std::ios::binary | std::ios::ate);
    if (fin.is_open()) {
        int32_t fileSize = fin.tellg();
        fin.close();
        return fileSize;
    }
    return 0;
}
}  // namespace SE
}  // namespace OHOS
